Skip to content

build: implement ios builds#77

Open
gBasil wants to merge 5 commits intoByteNess:mainfrom
gBasil:build/ios
Open

build: implement ios builds#77
gBasil wants to merge 5 commits intoByteNess:mainfrom
gBasil:build/ios

Conversation

@gBasil
Copy link

@gBasil gBasil commented Mar 19, 2026

I finally got iOS builds working! It turns out that only Keyring needed changes, and that go-keychain didn't need to be touched. I tested it on an iOS device and it works.

For posterity, my build command (against the basic example in the README) is:

SDKROOT=$(xcrun --sdk iphoneos --show-sdk-path) \
IPHONEOS_DEPLOYMENT_TARGET=10.0 \
GOOS=ios GOARCH=arm64 CGO_ENABLED=1 \
go build

The one thing in this PR I'm not certain about is is the change I made in keychain_darwin.go. Strangely, that changed is needed for compilation, as despite compiling for iOS, the Darwin file would seemingly be evaluated too, and Go would be unable to find the macOS-only symbols present there and error.

This was referenced Mar 19, 2026
@gBasil
Copy link
Author

gBasil commented Mar 20, 2026

The one unfortunate thing is that I've been unable to get it to build for older iOS versions (though it builds fine for newer ones). Changing SDKROOT to point to an SDK for iOS 14.5 and building causes this build error:

# example/hello
/opt/homebrew/Cellar/go/1.26.0/libexec/pkg/tool/darwin_arm64/link: running cc failed: exit status 1
/usr/bin/cc -Wl,-S -o $WORK/b001/exe/a.out -Qunused-arguments /var/folders/11/vf0w_3yx1pn3s6psnmvpm52c0000gn/T/go-link-4092325464/go.o /var/folders/11/vf0w_3yx1pn3s6psnmvpm52c0000gn/T/go-link-4092325464/000000.o /var/folders/11/vf0w_3yx1pn3s6psnmvpm52c0000gn/T/go-link-4092325464/000001.o /var/folders/11/vf0w_3yx1pn3s6psnmvpm52c0000gn/T/go-link-4092325464/000002.o /var/folders/11/vf0w_3yx1pn3s6psnmvpm52c0000gn/T/go-link-4092325464/000003.o /var/folders/11/vf0w_3yx1pn3s6psnmvpm52c0000gn/T/go-link-4092325464/000004.o /var/folders/11/vf0w_3yx1pn3s6psnmvpm52c0000gn/T/go-link-4092325464/000005.o /var/folders/11/vf0w_3yx1pn3s6psnmvpm52c0000gn/T/go-link-4092325464/000006.o /var/folders/11/vf0w_3yx1pn3s6psnmvpm52c0000gn/T/go-link-4092325464/000007.o /var/folders/11/vf0w_3yx1pn3s6psnmvpm52c0000gn/T/go-link-4092325464/000008.o /var/folders/11/vf0w_3yx1pn3s6psnmvpm52c0000gn/T/go-link-4092325464/000009.o /var/folders/11/vf0w_3yx1pn3s6psnmvpm52c0000gn/T/go-link-4092325464/000010.o /var/folders/11/vf0w_3yx1pn3s6psnmvpm52c0000gn/T/go-link-4092325464/000011.o /var/folders/11/vf0w_3yx1pn3s6psnmvpm52c0000gn/T/go-link-4092325464/000012.o /var/folders/11/vf0w_3yx1pn3s6psnmvpm52c0000gn/T/go-link-4092325464/000013.o /var/folders/11/vf0w_3yx1pn3s6psnmvpm52c0000gn/T/go-link-4092325464/000014.o /var/folders/11/vf0w_3yx1pn3s6psnmvpm52c0000gn/T/go-link-4092325464/000015.o /var/folders/11/vf0w_3yx1pn3s6psnmvpm52c0000gn/T/go-link-4092325464/000016.o /var/folders/11/vf0w_3yx1pn3s6psnmvpm52c0000gn/T/go-link-4092325464/000017.o -O2 -g -framework CoreFoundation -framework CoreFoundation -framework CoreFoundation -framework Security -framework CoreFoundation -framework Security -lresolv -O2 -g -framework CoreFoundation -O2 -g -ldl -framework CoreFoundation -framework Security
Undefined symbols for architecture arm64:
  "_SecTrustCopyCertificateChain", referenced from:
      _runtime.text in go.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

It seems to be related to this issue in the Go repo, which mentions this change where the crypto library moves to a newer API, that according to Apple's documentation is available in iOS 15.0+, which would restrict compilation to those versions. I've tried downgrading Go and the crypto version, but I still run into the same issue.

Copy link

@mbevc1 mbevc1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your contribution and I'm glad to hear you got it going.

Just a side note - Darwin keychain backend has tests. The iOS file adds new backend logic with no corresponding test file. Even a stub that only compiles and skips on non-iOS would help CI catch regressions in the future.

keychain_ios.go Outdated
Comment on lines +27 to +28
// Set the isAccessibleWhenUnlocked to the boolean value of
// KeychainAccessibleWhenUnlocked is a shorthand for setting the accessibility value.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this part of the same sentance, reads a bit weird 🤔

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is lifted straight from the old keychain.go:

keyring/keychain.go

Lines 44 to 45 in 505a3f7

// Set the isAccessibleWhenUnlocked to the boolean value of
// KeychainAccessibleWhenUnlocked is a shorthand for setting the accessibility value.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated this comment to read better.

passwordFunc PromptFunc

isSynchronizable bool
isAccessibleWhenUnlocked bool
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem to be initialised?

The keychain struct includes isSynchronizable, and Set does check it — but the init() function that constructs the struct never sets it from cfg. Looking at the Darwin implementation, cfg.KeychainSynchronizable is presumably used to populate this field. The iOS init currently omits this, meaning isSynchronizable will always be false even if a caller configures it. This looks like an oversight.

Copy link
Author

@gBasil gBasil Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is already the case with keychain.go. When making this PR, I simply copied over the original keyring.go, and removed everything that was either unused or macOS-specific. This slipped by me, but it also mirrors the behavior on mac, and the behavior that was already present.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the code, cfg.KeychainSynchronizable doesn't seem to actually be used anywhere, which I think is the root oversight. I've added support for it to both iOS & macOS.

@@ -0,0 +1,191 @@
//go:build ios && cgo
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You comment notes that iOS 15.0+ is effectively required due to a Go runtime dependency on SecTrustCopyCertificateChain. This is a meaningful constraint for downstream users, but it's not captured anywhere in the code (no comment, no doc, no README update). It would be worth at minimum adding a comment near the build tag, e.g.:

//go:build ios && cgo
// NOTE: Due to Go's crypto library requiring SecTrustCopyCertificateChain,
// this requires iOS 15.0 or later.

Copy link
Author

@gBasil gBasil Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The thing is, I'm not very familiar with building in Go, especially with CGO and Apple SDKs, so I'm not 100% certain that you strictly need to use a newer iOS version, but I personally haven't been able to figure out how to get around this. I'm sure it must be possible though. Thing is, I want to be able to build for older iOS, as I made this PR with the goal of helping get another project to compile for an iOS version below 15.

I do think a comment would be a good idea, perhaps even in the README, since that's far more likely to be read. But it should be warned somewhere that macOS 12.0+ is required too, since the API is only available there.

@gBasil
Copy link
Author

gBasil commented Mar 21, 2026

I don't know if you can run iOS binaries on macOS (they seem to just get SIGKILLed), and I don't think there are any iOS runners, so I think a stub would be needed. But I'm not sure what exactly you mean by that. Just a file like this?

//go:build ios

package keyring

@gBasil gBasil requested a review from mbevc1 March 21, 2026 20:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants